/**
 ******************************************************************************
 * @file	interface/fpga-2016.c
 * @brief	interface/fpga-2016.c

 * Copyright (C) 2017 桂林聚联科技有限公司, Inc. All Rights Reserved.
 fpga-2016 存储器通信

采用原始 fpga-2016 SPI通信协议

bug
    fpga 自身返回序列有缺陷，普通的控制命令容易错乱，主控端需要多次重复读取，
    返回OTDR数据是否有错误无法得知，
 *
 * @section Platform
 * 	-# linux-2.6
 * @section Library
 * 	-# null
 *
 * @section Depend
 *	-# spi_mxs.ko
 *	-# spidev.ko
 *	-# libpthread.so
 *
 * - 2016-10-21,MenglongWu,MenglongWoo@aliyun.com
*/

#include <autoconfig.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>

#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <stdio.h>

#include "proginfo.h"
// #include "fpga-tr700.h"
#include "printl.h"

#include "pthread.h"
// #include "fpga-otdr-cfg.h"
// #include "fpga_encode.h"
#include "port.h"
#include "fpga-common.h"
#include "fpga-private.h"
#include "encode-otdr.h"
// #include "encode-ocid.h"


extern int env_ignore_rx;

// Fix LS2K unsupport cs unchange
#define CONFIG_READ_1000_POINT (0)

#define SPI_TP_BEGIN           _IOR(SPI_IOC_MAGIC, 5, __u8)
#define SPI_TP_COMMIT          _IOR(SPI_IOC_MAGIC, 6, __u8)

// #define this_dbg(fmt, ...)     PRINTL(OTDR_DBG_LEVEL, C_DEBUG fmt C_NORMAL, ##__VA_ARGS__)
#define this_dbg(fmt, ...)

// #if defined(CONFIG_USE_DEBUG_ENV)
// #define ENV_PRINT_E(fmt, ...)                              \
// 	if (env_print_e) {                                     \
// 		_ctstprint(C_ERROR, C_NORMAL, fmt, ##__VA_ARGS__); \
// 	}
// #define ENV_PRINT_W(fmt, ...)                             \
// 	if (env_print_w) {                                    \
// 		_ctstprint(C_WARN, C_NORMAL, fmt, ##__VA_ARGS__); \
// 	}
// #else
// #define ENV_PRINT_E(fmt, ...)
// #define ENV_PRINT_w(fmt, ...)
// #endif


// static unsigned int __fpga_transfer(struct fpga_dev *dev, unsigned char cmd,
//                                     char *tbuf, int tlen,
//                                     char *rbuf, int rlen,
//                                     int wait);


// unsigned int _fpga_alive(struct fpga_dev *dev);
const char *dev_desc = "fpga-2016";
// char *otdr_cache = NULL;
/*
《fpga-2016 TR600plus—CPU与FPGA通信命令协议》 2016-11-4 协议格式
最小帧长度 10 Byte
-------------------------------------------------------------------------------
glink (5)  |  len (1) |  unuse1 (1)  |  cmd (1)  |  data (n)  |  checksum (2)
-------------------------------------------------------------------------------

《TR600plus—CPU与FPGA通信命令协议.doc》 2016-11-24 协议格式
最小帧长度 12 Byte
-------------------------------------------------------------------------------
glink (5)  |  len (2)  |  unuse1 (1)  | addr (1) |  cmd (1)  |  data (n)  |  checksum (2)
-------------------------------------------------------------------------------

FPGA返回格式
其中 cmd 固定为 0xf0
data 通常为 1-8 byte
-------------------------------------------------------------------------------
glink (5)  |  len (2)  |  unuse1 (1)  | addr (1) |  cmd (1)  |  data(n)
-------------------------------------------------------------------------------

*/
#include "fpga-common.h"


struct fpga_tr700_private
{
};

// #define MIN_RX_PACK_SIZE (12)		// 最小接收帧长度
#define MIN_RX_PACK_SIZE     (38)  // debug


// unsigned char txbuf[100];
// unsigned char rxbuf[4000];


/* OTDR 测试数据命令 */
#define OTDR_RETURN          (0xf0)
#define OTDR_RESET           (0xe0)

#define OTDR_PARAM           (0x10)
#define OTDR_START           (0x11)
#define OTDR_STOP            (0x12)
#define OTDR_IS_FINISH       (0x13)
#define OTDR_REDLASER        (0x14)
#define FPGA_ALIVE           OTDR_ALIVE
#define OTDR_COM_LASER       (0x15)
#define FPGA_VER             OTDR_VER
#define OTDR_ROTDR           (0x20)
#define OTDR_APD_TEMP        (0x21)
#define OTDR_POWER           (0x22)
#define OTDR_PULSE_ENCODE    (0x23)
// #define OTDR_RD_REG             (0x24)  // TF500 对寄存器芯片进行读操作

#define OTDR_ALARM_APPEAR    (0x25)  // TMS400 告警输出 数码管显示
#define OTDR_ALARM_DISAPPEAR (0x26)  // TMS400 告警取消

#define OTDR_WD_REG          (0x27)  // TF500 对寄存器芯片进行写操作 2018-8-27
#define OTDR_RD_REG          (0x28)  // TF500 对寄存器芯片进行读操作 2018-8-27

#define OCID_PARAM           (0x30)
#define OCID_LEVEL           (0x31)
#define OCID_START           (0x32)
#define OCID_STOP            OTDR_STOP
#define OCID_READ_DATA       (0x33)

/* 数据错误试着次数 */
#define RETRY                (3)


//*****************************************************************************
// 公共部分
//*****************************************************************************
#if 1 || defined(CONFIG_USE_DEBUG_ENV)
#if CONFIG_CPU_ORANGEPI
char *env_interface = "this-otdr-32k-orangepi";
#else
char *env_interface = "this-otdr-32k";
// char *env_interface         = "this-otdr-32k-raw-kernel";
#endif
int *env_fix_device        = "/dev/spidev1.0";
int  env_future_show       = 1;
int  env_otdr_dbg_level    = 0;
int  env_print_otdr_data   = 0;
int  env_dbg_tx            = 0;
int  env_dbg_rx            = 0;
int  env_dbg_bit_otdr_data = 0;
int  env_ignore_rx         = 0;
int  env_save_otdr         = 0;
int  env_print_e           = 0;
int  env_print_w           = 0;
int  env_lowpower_thread   = 0;
int  env_unuse_cksum       = 0;
int  env_speed             = 0;
#endif
char env_dev_led_run[128] = "\0";


struct env_val
{
    char *env;
    int  *val;
};

#if 1 || defined(CONFIG_USE_DEBUG_ENV)
struct env_val g_env_val[] = {
    { "DEVICE_SPI_FPGA_OTDR", &env_fix_device },
    { "DBG_P", &env_otdr_dbg_level },
    { "PRINT_OTDR_DATA", &env_print_otdr_data },
    { "DBG_TX", &env_dbg_tx },
    { "DBG_RX", &env_dbg_rx },
    { "DBG_BIT_OTDR_DATA", &env_dbg_bit_otdr_data },
    { "DBG_PRINT_E", &env_print_e },
    { "DBG_PRINT_W", &env_print_w },
    { "LOWPOWER_FPGA", &env_lowpower_thread },
    { "UNUSE_CKSUM", &env_unuse_cksum },
    { "FETURE_SHOW", &env_future_show },
    { "SAVE_OTDR", &env_save_otdr },
    { "SPEED", &env_speed },
    { "DBG_IGNORE_RX", &env_ignore_rx },
    {},
};
#endif

void fpga_update_env()
{
    char *env = NULL;

#if CONFIG_CPU_ORANGEPI
    env = getenv("DEVICE_SPI_FPGA_OTDR");
    if (env) {
	env_fix_device = env;
    }
#endif

#if 1 || defined(CONFIG_USE_DEBUG_ENV)

    env = getenv("DBG_P");
    if (env) {
	env_otdr_dbg_level = atoi(env);
    }
    env = getenv("PRINT_OTDR_DATA");
    if (env) {
	env_print_otdr_data = atoi(env);
    }
    env = getenv("DBG_TX");
    if (env) {
	env_dbg_tx = atoi(env);
    }
    env = getenv("DBG_RX");
    if (env) {
	env_dbg_rx = atoi(env);
    }
    env = getenv("DBG_BIT_OTDR_DATA");
    if (env) {
	env_dbg_bit_otdr_data = atoi(env);
    }
    env = getenv("DBG_PRINT_E");
    if (env) {
	env_print_e = atoi(env);
    }
    env = getenv("DBG_PRINT_W");
    if (env) {
	env_print_w = atoi(env);
    }
#endif
    env = getenv("DEVICE_LED_RUN");
    if (env) {
	strcpy(env_dev_led_run, env);
	// printf("环境变量成功\r\n");
    }
    else {
	// printf("没有环境变量\r\n");
    }

    env = getenv("LOWPOWER_FPGA");
    if (env) {
	env_lowpower_thread = (int)env;
    }

    env = getenv("UNUSE_CKSUM");
    if (env) {
	env_unuse_cksum = atoi(env);
	printf("env_unuse_cksum %d\r\n", env_unuse_cksum);
    }
    env = getenv("DEVICE_FPGA_INTERFACE");
    if (env) {
	env_interface = env;
	printf("DEVICE_FPGA_INTERFACE %s\r\n", env_interface);
    }
    env = getenv("SAVE_OTDR");
    if (env) {
	env_save_otdr = atoi(env);
	printf("SAVE_OTDR %d\r\n", env_save_otdr);
    }
    env = getenv("SPEED");
    if (env) {
	env_speed = atoi(env);
    }
    env = getenv("DBG_IGNORE_RX");
    if (env) {
	env_ignore_rx = atoi(env);
    }
}

void fpga_show_env()
{
    struct env_val *p = g_env_val;
    printf("当前环境变量\r\n");
    while (p->env) {
	printf("\t%s=%d\r\n", p->env, *p->val);
	p++;
    }
}


static void __attribute__((constructor(INIT_ENV))) _load_env()
{
    fpga_update_env();
#if CONFIG_LOW_POWER_TASK_EN
    low_power_task();
#endif
}


int _fpga_send_data(
	struct fpga_dev *dev,
	char             cmd,
	void            *t_buf,
	int              tlen,
	void            *r_buf,
	int              rlen)
{
    char rbuf[MIN_RX_PACK_SIZE];
    // __fpga_transfer(dev, cmd, t_buf, tlen, r_buf, rlen, _1MS * 50);
    __fpga_transfer(dev, cmd, t_buf, tlen, r_buf, rlen, _1MS * 2);
    char	 *pbuf = r_buf;
    unsigned char ack  = ACK_CODE(pbuf);
    if (env_ignore_rx) {
	ack = 0xaa;
    }
    switch (ack) {
    case 0xaa:
	this_dbg("%s() OK\r\n", __FUNCTION__);
	return 0;
    case 0x55:
	ENV_PRINT_W("Error\r\n");
	return -1;
    default:
	ENV_PRINT_E("unknow [ack] %d\r\n", ack);
	return -1;
    }
    return -1;
}
int fpga_send_data(
	struct fpga_dev *dev,
	char             cmd,
	void            *t_buf,
	int              tlen,
	void            *r_buf,
	int              rlen)
{
    mutex_lock(&dev->mutex);
    int ret = _fpga_send_data(dev, cmd, t_buf, tlen, r_buf, rlen);
    mutex_unlock(&dev->mutex);
    return ret;
}

/* 本接口可支持的软件版本 */
struct _fpga_table
{
    unsigned long soft_ver;
    unsigned long hw_ver;
    char	 *desc;
};


void memcpy_char(char *dst, char *src, int len)
{
    for (int i = 0; i < len; i++) {
	*dst = *src;
	dst++;
	src++;
    }
}


int fpga_close(struct fpga_dev *dev)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    // do_fpga_power(0);
    fpga_if_suspend(dev);
    mutex_destroy(&dev->mutex);
    os_close(dev->fd);


    // 全局的可能会引起其他线程崩溃，不同应用之间不用担心，依靠写时拷贝
#if 0
	os_free(dev);
	dev = NULL;
	os_free(otdr_cache);
	otdr_cache = NULL;
	printf("otdr_cache %x\r\n", otdr_cache);
#else
    // os_free(dev->otdr_cache);
    // dev->otdr_cache = NULL;
    dev->interface->pfun_release(dev);
    free(dev->interface);
    os_free(dev);
    dev                = NULL;
#endif
    return 0;
}

int fpga_open_interface(char *device, struct fpga_dev **p_in_dev, unsigned long ispeed, char *ifname)
{
    // todo spinlock

#if CONFIG_CPU_ORANGEPI
    unsigned int  mode = 0;
    unsigned char bits = 32;
#else
    unsigned char mode = 0;
    unsigned char bits = 8;
#endif
    unsigned long speed = 16 * 1000 * 1000;
    // unsigned short delay;
    int fd;

    if (env_speed > 1000000) {
	speed = env_speed;
    }
    else {
	if (ispeed) {
	    speed = ispeed;
	}
    }
    // do_fpga_power(1);
    fpga_power_up();
#if CONFIG_CPU_ORANGEPI
    fd = os_open(env_fix_device, O_RDWR);
#else
    fd                 = os_open(device, O_RDWR);
#endif
    if (fd == 0) {
	return -1;
    }

    // mode = SPI_MODE_3;//ok
    mode = 0;  // ok
               // // mode = SPI_MODE_1;//error
	       // mode = SPI_MODE_0;//ok
#if CONFIG_CPU_ORANGEPI
    ioctl(fd, SPI_IOC_WR_MODE32, &mode);
    ioctl(fd, SPI_IOC_RD_MODE32, &mode);
#else
    ioctl(fd, SPI_IOC_WR_MODE, &mode);
    ioctl(fd, SPI_IOC_RD_MODE, &mode);
#endif
    ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
    ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);

    struct fpga_dev *dev;
    dev = (struct fpga_dev *)malloc(sizeof(struct fpga_dev));
    if (dev == NULL) {
	goto _fail1;
    }
    bzero(dev, sizeof(struct fpga_dev));

    // todo spinlock
    dev->fd = fd;
    mutex_init(&dev->mutex, NULL);
    // {
    // 	struct fpga_dev *pdev = pdev;
    // 	mutex_unlock(&pdev->mutex);
    // }
    if (-1 == com_fpga_alive(dev)) {
	goto _fail2;
    }
    *p_in_dev = dev;
    // (*dev)->interface = fpga_if_append("this-common");
    // (*dev)->interface = fpga_if_append("this-otdr-64k");
    // (*dev)->interface = fpga_if_append("this-otdr-32k");

    struct fpga_if *newif = malloc(sizeof(struct fpga_if) * 1000);
    memset(newif, 1, sizeof(struct fpga_if) * 1000);
    memcpy(newif, fpga_if_append(ifname), sizeof(struct fpga_if));
    (*p_in_dev)->interface = newif;

    fpga_if_resume(*p_in_dev);
    // (*dev)->otdr_cache = (char *)malloc(LEN_OTDR_CACHE);
    fpga_if_probe(*p_in_dev);

    // if ((*dev)->otdr_cache == NULL) {
    // 	ENV_PRINT_E("malloc otdr_cache \n");
    // 	exit(1);
    // }
    return 0;
_fail1:
    os_close(fd);
    return -1;
_fail2:
    fpga_close(p_in_dev);
    return -2;
}
int fpga_open(char *device, struct fpga_dev **dev, unsigned long ispeed)
{
    return fpga_open_interface(device, dev, ispeed, env_interface);
}

void com_fpga_save_32bit(char *fname, unsigned char *data, unsigned long len)
{
    unsigned int *plong;
    unsigned int  loop = len >> 2;
    unsigned int  tmp;
    FILE	 *fp;

    fp    = fopen(fname, "wb");
    plong = (unsigned int *)data;

    fprintf(fp, "data\r\n");
    for (int i = 0; i < loop; i++) {
	tmp = (unsigned int)data[0] +
	      (unsigned int)(data[1] << 8) +
	      (unsigned int)(data[2] << 16) +
	      (unsigned int)(data[3] << 24);

	fprintf(fp, "%8.8ld\r\n", *plong);
	plong++;
    }
    fclose(fp);
    return;
}
void fpga_save_32bit(char *fname, unsigned char *data, unsigned long len)
{
    com_fpga_save_32bit(fname, data, len);
}
//*****************************************************************************
// End 公共部分
//*****************************************************************************

//*****************************************************************************
// OTDR 系列接口
//*****************************************************************************

#define CONFIG_FPGA_SHIFT 1
/**
 * @brief	由于帧错位，在一串接受数据里找到帧头
 * @param	data 错位的帧
 * @param	limit 只在limit之前查找帧头，data 在 limit 后还有数据，但不足一帧
 * @retval	其他 找到帧
 * @retval	<0 找不到帧
 */

// static
int _find_frame_start(char *data, int limit)
{
#if defined(CONFIG_FPGA_SHIFT)
    char *pdata;
    for (int i = 0; i < limit; i++) {
	pdata = data + i;
	if ('G' == pdata[0] &&
	    'L' == pdata[1] &&
	    'I' == pdata[2] &&
	    'N' == pdata[3] &&
	    'K' == pdata[4]) {
	    this_dbg("%s() find frame head [offset %d byte]\r\n", __FUNCTION__, i);
	    return i;
	}
    }
    return -1;
#else
    return -1;
#endif
}
/**
 * @brief	寻找OTDR数据开始位置
 * @param	data
 * @param	limit 最大检测长度
 * @retval	null
 * @remarks
 * @see
 */
#if defined(CONFIG__find_otdr_data_start)
static int _find_otdr_data_start(char *data, int limit)
{
#if 1  // defined(CONFIG_FPGA_SHIFT)
    char *pdata;
    for (int i = 0; i < limit; i++) {
	pdata = data + i;
	if (DATA_FLAG == pdata[0] &&
	    DATA_FLAG == pdata[4] &&
	    DATA_FLAG == pdata[8]) {
	    if (i != 0) {
		this_dbg("%s() find otdr data head [offset %d byte]\r\n", __FUNCTION__, i);
	    }
	    return i;
	}
    }
    return -1;
#else
    return 0;
#endif
}
#endif


// int fpga_otdr_isfinish(struct fpga_dev *dev, bool *val)
// {
// 	assert(dev != NULL);
// 	// assert(dev->desc == dev_desc);

// 	// char rbuf[MIN_RX_PACK_SIZE + 6];
// 	char rbuf[MIN_RX_PACK_SIZE];

// 	mutex_lock(&dev->mutex);
// 	_fpga_transfer(dev, OTDR_IS_FINISH,
// 	               &dev->ch, sizeof(dev->ch),
// 	               rbuf, ARRAY_SIZE(rbuf) );
// 	mutex_unlock(&dev->mutex);

// 	unsigned char ack;
// 	int offset = 0;
// 	int retry = 0;

// 	*val = false;
// _CheckFrame:
// 	;
// 	ack = ACK_CODE(rbuf + offset);
// 	retry++;
// 	switch (ack) {
// 	case 0xaa:
// 		dev->checksum = _STREAM_TO_32(&rbuf[CHKSUM_OFFSET]);
// 		dev->cum_count = _STREAM_TO_16(&rbuf[CUM_COUNT_OFFSET]);
// 		*val = true;
// 		return 0;
// 	case 0x55:
// 		dev->checksum = 0;
// 		dev->cum_count = 0;
// 		*val = false;
// 		ENV_PRINT_E("Error\r\n");
// 		return 0;
// 	default:
// 		offset = _find_frame_start(rbuf, ARRAY_SIZE(rbuf) / 2);
// 		if (retry < RETRY || -1 == offset) {
// #if defined(CONFIG_OTDR_PRINT_RX) && defined(CONFIG_ISFINISH_RX)
// 			PrintfMemory((uint8_t *)rbuf, ARRAY_SIZE(rbuf));
// 			ENV_PRINT_E("unknow\r\n");
// #endif
// 			offset = 0;
// 			return -1;
// 		} else {
// 			goto _CheckFrame;
// 		}
// 	}
// 	return -1;
// }


/**
 * @brief	读取OTDR温度
 * @param	val 温度值被扩大100倍，50.23℃ -> 50230
 * @retval	null
 * @remarks
 * @see
 */

int fpga_otdr_temp(struct fpga_dev *dev, int *val)
{
    assert(dev != NULL);
    // assert(dev->desc == dev_desc);

    // char rbuf[MIN_RX_PACK_SIZE + 6];
    char          rbuf[MIN_RX_PACK_SIZE];
    unsigned char ack;
    int           offset = 0;
    int           retry  = 0;
    char          t;  // 温度带符号

    *val = false;
    for (int retry = 0; retry < RETRY; retry++) {
	mutex_lock(&dev->mutex);
	__fpga_transfer(dev, OTDR_APD_TEMP, NULL, 0, rbuf, ARRAY_SIZE(rbuf), 10000);
	mutex_unlock(&dev->mutex);

	ack = ACK_CODE(rbuf + offset);
	retry++;
	switch (ack) {
	case 0xaa:
#if 1 || MIPS
	    /*
	     12B：全0
	     13B：

	     当13B最高位为0时，直接读取，最高位1位1，取反-256得到温度，下面的例子表示-56度
	     12B  | 13B
	     0x00     | 0xc8
	    */
	    // t = rbuf[13];
	    t = rbuf[12];  //再北京临时修改
	    if (t < 0) {
		t = t - 256;
	    }
	    *val = t * 1000;
	    // printf("%x %x %d\r\n", rbuf[12], rbuf[13], *val);
#else
	    *val = rbuf[12] * 1000 + rbuf[13] * 10;
#endif
	    // printf("*val %x %x\r\n", *val, rbuf[12]);
	    return 0;
	case 0x55:
	    ENV_PRINT_W("Error\r\n");
	    return 0;
	default:
	    ENV_PRINT_E("unknow\r\n");
	    break;
	}
    }
    return -1;
}

/*****************************************************************************
    设置 OTDR 测试参数 功能入口 fpga_otdr_param

 fpga_otdr_param
    _encode_dist_2_pulse/_encode_self_pulse
    _encode_dist_2_sample_freq/_encode_self_sample_freq
    _encode_laser
    _encode_adopt
    _encode_add_cnt
    _encode_power
    _encode_amp
    _encode_apd_vol
    _encode_slot
    _encode_ch
*****************************************************************************/
// static short _encode_laser(struct fpga_test_param *val);
// static short _encode_dist_2_pulse(struct fpga_test_param *val);
// static short _encode_self_pulse(struct fpga_test_param *val);
// static char  _encode_dist_2_sample_freq(struct fpga_test_param *val);
// static char  _encode_self_sample_freq(struct fpga_test_param *val);
// static char  _encode_adopt(struct fpga_test_param *val);
// static short  _encode_add_cnt(struct fpga_test_param *val);
// static char  _encode_amp(struct fpga_test_param *val);
// static char  _encode_apd_vol(struct fpga_test_param *val);
// static char  _encode_power(struct fpga_test_param *val);
// static char  _encode_slot(struct fpga_test_param *val);
// static char  _encode_ch(struct fpga_test_param *val);

/*
  struct _fpga_test_param_tx 内容依据《TR600plus—CPU与FPGA通信命令协议.doc》
  2016-11-24 协议格式而定

  实际发送 "数据段" 内容
 转译 struct fpga_test_param  用fpga_otdr_param() 屏蔽协议层、与协议无关
*/
// struct _fpga_test_param_tx {
// 	unsigned short laser;///< 激光器通道
// 	unsigned short pulse;
// 	unsigned short dist;
// 	// unsigned char freq;
// 	// unsigned char adopt_pt;
// 	unsigned short add_ms;
// 	char power;
// 	char amp;
// 	char apd_vol;
// 	char slot;
// 	char ch;	///< 光开关通道
// 	char unuse1, unuse2, unuse3;
// };

// struct _fpga_ocid_param_tx {
// 	char ch;
// 	short post;       // 位置（由FPGA自己决定起始、结束位置）
// 	// int post_from;  // 起始位置（由ARM处理器决定两位置）
// 	// int post_to;    // 结束位置（由ARM处理器决定两位置）
// } __attribute__ ((__packed__));

// static short _encode_laser(struct fpga_test_param *val)
// {
// 	// assert(1310 == val->laser_ch ||
// 	//        1550 == val->laser_ch ||
// 	//        1490 == val->laser_ch ||
// 	//        1625 == val->laser_ch ||
// 	//        1300 == val->laser_ch ||
// 	//        // 换一种描述方式
// 	//        1 == val->laser_ch ||
// 	//        2 == val->laser_ch ||
// 	//        3 == val->laser_ch ||
// 	//        4 == val->laser_ch ||
// 	//        5 == val->laser_ch);

// 	return val->laser_ch;
// }


// // 十进制转BCD码，并以16进制表示
// unsigned short __dec_2_bcd(unsigned short dec)
// {
// 	unsigned short bcd = 0, tmp;

// 	// tmp = dec / 1000;
// 	// dec = dec % 1000;
// 	// if (tmp) {
// 	// 	tmp = tmp << 12;
// 	// }

// 	tmp = dec / 100;
// 	dec = dec % 100;
// 	if (tmp) {
// 		tmp = tmp << 8;
// 	}
// 	bcd += tmp;

// 	tmp = dec / 10;
// 	dec = dec % 10;
// 	if (tmp) {
// 		tmp = tmp << 4;
// 	}
// 	bcd += tmp;

// 	bcd += dec;
// 	return bcd;
// }


/*
 * 量程（km） 0.3          1            2      5    ...    300          400
 * 编码      300         0x8000+1  0x8000+2  0x8000+5    0x8000+300  0x8000+400
 *          (十进制)     十六进制
 */
// static short _encode_pulse(struct fpga_test_param *val)
// {
// 	switch (val->pulse) {
// 	case 5:
// 		return val->pulse;
// 	case 10:
// 		return val->pulse;
// 	}

// 	return 0x8000 + val->pulse / 20;
// }

// static short _encode_dist(struct fpga_test_param *val)
// {

// 	if (val->dist == 300) {
// 		return val->dist;
// 	}

// 	return 0x8000 + val->dist / 1000;
// }


// static short _encode_self_pulse(struct fpga_test_param *val)
// {
// 	return val->pulse;
// }


// static short _encode_self_dist(struct fpga_test_param *val)
// {
// 	return val->dist;
// }


// **************************************************************************


// static char _encode_adopt(struct fpga_test_param *val)
// {
// 	switch(val->adopt_pt) {
// 	case 32000:
// 		return 8;
// 		break;
// 	case 4000:
// 		return 1;
// 		break;
// 	case 8000:
// 		return 2;
// 		break;
// 	case 16000:
// 		return 4;
// 		break;
// 	case 64000:
// 		return 16;
// 		break;
// 	case 128000:
// 		return 32;
// 		break;
// 	case 256000:
// 		return 64;
// 		break;
// 	}
// 	return 8;
// }

// static short _encode_add_cnt(struct fpga_test_param *val)
// {
// 	return val->add_cnt;
// }


//**************************************************************
// 有效参数等待 FPGA 解释
// 未必是下面的有效值
// #define UNUSE_BIT (0)

// #define AMP_LOW_ACTIVE_LV1   (CFG_AMP_LOW_ACTIVE_LV1)	// 光耦开关低电平有效
// #define AMP_LOW_ACTIVE_LV2   (CFG_AMP_LOW_ACTIVE_LV2)
// #define AMP_LOW_ACTIVE_LV3   (CFG_AMP_LOW_ACTIVE_LV3)
// #define AMP_LOW_ACTIVE_LV4   (CFG_AMP_LOW_ACTIVE_LV4)


// #define AMP_B0_TO_SW	(CFG_AMP_B0_TO_SW)	// bit0 映射到amp编码值 0x80上
// #define AMP_B1_TO_SW	(CFG_AMP_B1_TO_SW)
// #define AMP_B2_TO_SW	(CFG_AMP_B2_TO_SW)
// #define AMP_B3_TO_SW	(CFG_AMP_B3_TO_SW)
// #define AMP_B4_TO_SW	(CFG_AMP_B4_TO_SW)
// #define AMP_B5_TO_SW	(CFG_AMP_B5_TO_SW)
// #define AMP_B6_TO_SW	(CFG_AMP_B6_TO_SW)
// #define AMP_B7_TO_SW	(CFG_AMP_B7_TO_SW)

// #define AMP_B8_TO_SW	(CFG_AMP_B8_TO_SW)
// #define AMP_B9_TO_SW	(CFG_AMP_B9_TO_SW)
// #define AMP_B10_TO_SW	(CFG_AMP_B10_TO_SW)
// #define AMP_B11_TO_SW	(CFG_AMP_B11_TO_SW)
// #define AMP_B12_TO_SW	(CFG_AMP_B12_TO_SW)
// #define AMP_B13_TO_SW	(CFG_AMP_B13_TO_SW)
// #define AMP_B14_TO_SW	(CFG_AMP_B14_TO_SW)
// #define AMP_B15_TO_SW	(CFG_AMP_B15_TO_SW)

// #define AMP_B16_TO_SW	(CFG_AMP_B16_TO_SW)
// #define AMP_B17_TO_SW	(CFG_AMP_B17_TO_SW)
// #define AMP_B18_TO_SW	(CFG_AMP_B18_TO_SW)
// #define AMP_B19_TO_SW	(CFG_AMP_B19_TO_SW)
// #define AMP_B20_TO_SW	(CFG_AMP_B20_TO_SW)
// #define AMP_B21_TO_SW	(CFG_AMP_B21_TO_SW)
// #define AMP_B22_TO_SW	(CFG_AMP_B22_TO_SW)
// #define AMP_B23_TO_SW	(CFG_AMP_B23_TO_SW)

// #define AMP_B24_TO_SW	(CFG_AMP_B24_TO_SW)
// #define AMP_B25_TO_SW	(CFG_AMP_B25_TO_SW)
// #define AMP_B26_TO_SW	(CFG_AMP_B26_TO_SW)
// #define AMP_B27_TO_SW	(CFG_AMP_B27_TO_SW)
// #define AMP_B28_TO_SW	(CFG_AMP_B28_TO_SW)
// #define AMP_B29_TO_SW	(CFG_AMP_B29_TO_SW)
// #define AMP_B30_TO_SW	(CFG_AMP_B30_TO_SW)
// #define AMP_B31_TO_SW	(CFG_AMP_B31_TO_SW)

// // amp 各放大级别在 encode 里的有效掩码
// #define AMP_MASK_LV1 (CFG_AMP_MASK_LV1)
// #define AMP_MASK_LV2 (CFG_AMP_MASK_LV2)
// #define AMP_MASK_LV3 (CFG_AMP_MASK_LV3)
// #define AMP_MASK_LV4 (CFG_AMP_MASK_LV4)


// static char _encode_amp(struct fpga_test_param *val)
// {
// 	// 限制在5个可控档位以内
// 	char b0, b1, b2, b3, b4, b5, b6, b7;// 各比特位
// 	char level;
// 	char encode_lv1 = 0, encode_lv2 = 0, encode_lv3 = 0, encode_lv4 = 0;
// 	char encode = 0;

// #if AMP_MASK_LV1
// 	level = val->amp & 0xff;
// 	b0 = (level & 0x01) ? AMP_B0_TO_SW : 0;
// 	b1 = (level & 0x02) ? AMP_B1_TO_SW : 0;
// 	b2 = (level & 0x04) ? AMP_B2_TO_SW : 0;
// 	b3 = (level & 0x08) ? AMP_B3_TO_SW : 0;
// 	b4 = (level & 0x10) ? AMP_B4_TO_SW : 0;
// 	b5 = (level & 0x20) ? AMP_B5_TO_SW : 0;
// 	b6 = (level & 0x40) ? AMP_B6_TO_SW : 0;
// 	b7 = (level & 0x80) ? AMP_B7_TO_SW : 0;

// #if (AMP_LOW_ACTIVE_LV1 == 1)
// 	encode_lv1 =  ~(b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7);// 硬件高电平有效
// #else
// 	encode_lv1 =   (b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7);// 硬件低电平有效
// #endif
// 	encode_lv1 &= AMP_MASK_LV1;// 去掉无用 bit
// #endif // end AMP_MASK_LV1


// #if AMP_MASK_LV2
// 	level = (val->amp >> 8 ) & 0xff;
// 	b0 = (level & 0x01) ? AMP_B8_TO_SW : 0;
// 	b1 = (level & 0x02) ? AMP_B9_TO_SW : 0;
// 	b2 = (level & 0x04) ? AMP_B10_TO_SW : 0;
// 	b3 = (level & 0x08) ? AMP_B11_TO_SW : 0;
// 	b4 = (level & 0x10) ? AMP_B12_TO_SW : 0;
// 	b5 = (level & 0x20) ? AMP_B13_TO_SW : 0;
// 	b6 = (level & 0x40) ? AMP_B14_TO_SW : 0;
// 	b7 = (level & 0x80) ? AMP_B15_TO_SW : 0;
// #if (AMP_LOW_ACTIVE_LV2 == 1)
// 	encode_lv2 =  ~(b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7);
// #else
// 	encode_lv2 =   (b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7);
// #endif
// 	encode_lv2 &= AMP_MASK_LV2;
// #endif // end AMP_MASK_LV2


// #if AMP_MASK_LV3
// 	level = (val->amp >> 16 ) & 0xff;
// 	b0 = (level & 0x01) ? AMP_B16_TO_SW : 0;
// 	b1 = (level & 0x02) ? AMP_B17_TO_SW : 0;
// 	b2 = (level & 0x04) ? AMP_B18_TO_SW : 0;
// 	b3 = (level & 0x08) ? AMP_B19_TO_SW : 0;
// 	b4 = (level & 0x10) ? AMP_B20_TO_SW : 0;
// 	b5 = (level & 0x20) ? AMP_B21_TO_SW : 0;
// 	b6 = (level & 0x40) ? AMP_B22_TO_SW : 0;
// 	b7 = (level & 0x80) ? AMP_B23_TO_SW : 0;
// #if (AMP_LOW_ACTIVE_LV3 == 1)
// 	encode_lv3 =  ~(b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7);
// #else
// 	encode_lv3 =   (b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7);
// #endif
// 	encode_lv3 &= AMP_MASK_LV3;
// #endif // end AMP_MASK_LV3


// #if AMP_MASK_LV4
// 	level = (val->amp >> 24 ) & 0xff;
// 	b0 = (level & 0x01) ? AMP_B24_TO_SW : 0;
// 	b1 = (level & 0x02) ? AMP_B25_TO_SW : 0;
// 	b2 = (level & 0x04) ? AMP_B26_TO_SW : 0;
// 	b3 = (level & 0x08) ? AMP_B27_TO_SW : 0;
// 	b4 = (level & 0x10) ? AMP_B28_TO_SW : 0;
// 	b5 = (level & 0x20) ? AMP_B29_TO_SW : 0;
// 	b6 = (level & 0x40) ? AMP_B30_TO_SW : 0;
// 	b7 = (level & 0x80) ? AMP_B31_TO_SW : 0;

// #if (AMP_LOW_ACTIVE_LV4 == 1)
// 	encode_lv4 =  ~(b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7);
// #else
// 	encode_lv4 =   (b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7);
// #endif
// 	encode_lv4 &= AMP_MASK_LV4;
// #endif // end AMP_MASK_LV4

// 	encode = (encode_lv1 + encode_lv2 + encode_lv3 + encode_lv4) &
// 	         (AMP_MASK_LV1 + AMP_MASK_LV2 + AMP_MASK_LV3 + AMP_MASK_LV4);

// 	return encode;
// }


// //**************************************************************
// // 有效参数等待 FPGA 解释
// // 未必是下面的有效值

// #define APD_LOW_ACTIVE   (CFG_APD_LOW_ACTIVE)	// 光耦开关低电平有效
// #define APD_LOW_ACTIVE   (CFG_APD_LOW_ACTIVE)
// #define APD_LOW_ACTIVE   (CFG_APD_LOW_ACTIVE)
// #define APD_LOW_ACTIVE   (CFG_APD_LOW_ACTIVE)


// #define APD_B0_TO_SW	(CFG_APD_B0_TO_SW)	// bit0 映射到APD编码值 0x80上
// #define APD_B1_TO_SW	(CFG_APD_B1_TO_SW)
// #define APD_B2_TO_SW	(CFG_APD_B2_TO_SW)
// #define APD_B3_TO_SW	(CFG_APD_B3_TO_SW)
// #define APD_B4_TO_SW	(CFG_APD_B4_TO_SW)
// #define APD_B5_TO_SW	(CFG_APD_B5_TO_SW)
// #define APD_B6_TO_SW	(CFG_APD_B6_TO_SW)
// #define APD_B7_TO_SW	(CFG_APD_B7_TO_SW)

// #define APD_MASK (CFG_APD_MASK)

// static char _encode_apd_vol(struct fpga_test_param *val)
// {
// 	char b0, b1, b2, b3, b4, b5, b6, b7;// 各比特位
// 	char level;
// 	char encode = 0;

// #if APD_MASK
// 	level = val->apd_vol & 0xff;
// 	b0 = (level & 0x01) ? APD_B0_TO_SW : 0;
// 	b1 = (level & 0x02) ? APD_B1_TO_SW : 0;
// 	b2 = (level & 0x04) ? APD_B2_TO_SW : 0;
// 	b3 = (level & 0x08) ? APD_B3_TO_SW : 0;
// 	b4 = (level & 0x10) ? APD_B4_TO_SW : 0;
// 	b5 = (level & 0x20) ? APD_B5_TO_SW : 0;
// 	b6 = (level & 0x40) ? APD_B6_TO_SW : 0;
// 	b7 = (level & 0x80) ? APD_B7_TO_SW : 0;

// #if (APD_LOW_ACTIVE == 1)
// 	encode =  ~(b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7);// 硬件高电平有效
// #else
// 	encode =   (b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7);// 硬件低电平有效
// #endif
// 	encode &= APD_MASK;// 去掉无用 bit
// #endif // end APD_LOW_ACTIVE

// 	return encode;
// }

// char _list_power[] = {
// 	0,
// 	OTDR_LASER_PW_LV1,
// 	OTDR_LASER_PW_LV2,
// 	OTDR_LASER_PW_LV3,
// 	OTDR_LASER_PW_LV4,
// };
// static char _encode_power(struct fpga_test_param *val)
// {
// 	assert(val->power < ARRAY_SIZE(_list_power));
// 	assert(0 <= val->power);

// 	return _list_power[(uint32_t)val->power];

// }
// static char _encode_slot(struct fpga_test_param *val)
// {
// 	// PRINTD("do nothing");
// #if defined(CONFIG_EN_CAP)
// 	return val->cap;
// #else
// 	return 0;
// #endif
// }
// static char _encode_ch(struct fpga_test_param *val)
// {
// 	// PRINTD("do nothing");
// 	return val->panel_ch;
// }

// static unsigned short _encode_add_ms(struct fpga_test_param *val)
// {
// 	return val->add_ms;
// }

// #define FREQ_OFFSET (12)
// #define ADOPT_PT_OFFSET (14)

// inline  unsigned long _decode_freq(char *rbuf)
// {
// 	unsigned short section;
// 	memcpy(&section, rbuf + FREQ_OFFSET, sizeof(unsigned short));
// 	switch(section) {
// 	case 12:
// 		return 12500000;
// 	case 6:
// 		return 6250000;
// 	default:
// 		break;
// 	}
// 	return section * 1000000;
// }
// inline unsigned short _decode_adopt_pt(char *rbuf)
// {
// 	unsigned short section;
// 	memcpy(&section, rbuf + ADOPT_PT_OFFSET, sizeof(unsigned short));
// 	return 	section * 1000;
// }


// int fpga_ocvl_param(struct fpga_dev *dev, struct fpga_test_param *val)
// {
//     mutex_lock(&dev->mutex);
//     // _clear_fpga_cache(dev->fd);
//     int ret = -1;//_fpga_otdr_param(dev, val, OCVL_PARAM);
//     // int ret = 0;
//     mutex_unlock(&dev->mutex);
//     return ret;
// }
/*****************************************************************************
    End 设置 OTDR 测试参数 功能入口 fpga_otdr_param
****************************************************************************/

// 请求和开始测试一起
// int fpga_request_test(struct fpga_dev *dev, struct fpga_test_param *val)
// {
// 	assert(dev != NULL);
// 	assert(dev->desc == dev_desc);

// 	mutex_lock(&dev->mutex);
// 	if (0 == _fpga_otdr_param(dev, val) &&
// 	    0 == _fpga_otdr_start(dev)
// 	    // TODO 等待数据准备完好，并带超市机制
// 	   ) {
// 		mutex_unlock(&dev->mutex);
// 		return 0;
// 	} else {
// 		mutex_unlock(&dev->mutex);
// 		return -1;
// 	}
// }

int fpga_red_laser(struct fpga_dev *dev, int val)
{
    // PRINT_FUTURE("sss");
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    assert(val == OTDR_RL_OFF || val == OTDR_RL_ON || val == OTDR_RL_1HZ || val == OTDR_RL_10HZ);

    char tbuf[2];
    // char rbuf[MIN_RX_PACK_SIZE];
    char rbuf[12];

    tbuf[0] = val;
    tbuf[1] = 0;
    mutex_unlock(&dev->mutex);
    _fpga_transfer(dev, OTDR_REDLASER, tbuf, ARRAY_SIZE(tbuf), rbuf, ARRAY_SIZE(rbuf));
    mutex_unlock(&dev->mutex);

    unsigned char ack = ACK_CODE(rbuf);

    switch (ack) {
    case 0xaa:
	this_dbg("%s() OK\r\n", __FUNCTION__);
	return 0;
    case 0x55:
	ENV_PRINT_W("Error\r\n");
	return -1;
    default:
	ENV_PRINT_E("unknow\r\n");
	return -1;
    }
}


/**
 * @brief	FPGA电源
 * @param	val 1 打开，0关闭
 *
 * @bug
 * 			以后这个命令可能演化成FPGA电源控制，
 *			使用这个命令关闭电源后，目前状态下FPGA接收的命令全是正确，
 *			导致通信光检测一直有通信光
 */
// int fpga_power(struct fpga_dev *dev, int val)
// {
// 	assert(dev != NULL);
// 	assert(dev->desc == dev_desc);

// 	char tbuf[2];
// 	char rbuf[MIN_RX_PACK_SIZE];

// 	tbuf[0] = val;
// 	tbuf[1] = 0;
// 	mutex_unlock(&dev->mutex);
// 	_fpga_transfer(dev, OTDR_POWER,
// 	               // tbuf, ARRAY_SIZE(tbuf),
// 	               NULL, 0,
// 	               rbuf, ARRAY_SIZE(rbuf) );
// 	mutex_unlock(&dev->mutex);

// 	unsigned char ack = ACK_CODE(rbuf);

// 	switch (ack) {
// 	case 0xaa:
// 		this_dbg("%s() OK\r\n", __FUNCTION__);
// 		return 0;
// 	case 0x55:
// 		ENV_PRINT_W("Error\r\n");
// 		return -1;
// 	default:
// 		ENV_PRINT_E("unknow\r\n");
// 		return -1;
// 	}
// }
#if defined(CONFIG_fpga_pulse)
int fpga_pulse(struct fpga_dev *dev, char (*val)[OTDR_PULSE_ARRAY])
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    char tbuf[OTDR_PULSE_ARRAY];
    char rbuf[MIN_RX_PACK_SIZE];

    memcpy(tbuf, val, OTDR_PULSE_ARRAY);
    mutex_unlock(&dev->mutex);
    _fpga_transfer(dev, OTDR_PULSE_ENCODE, tbuf, ARRAY_SIZE(tbuf), rbuf, ARRAY_SIZE(rbuf));
    mutex_unlock(&dev->mutex);

    unsigned char ack = ACK_CODE(rbuf);

    switch (ack) {
    case 0xaa:
	this_dbg("%s() OK\r\n", __FUNCTION__);
	return 0;
    case 0x55:
	ENV_PRINT_W("Error\r\n");
	return -1;
    default:
	ENV_PRINT_E("unknow\r\n");
	return -1;
    }
}
#endif
/**
 * @brief	计算发送数据的校验码
 * @param[in]	data 待校验内容
 * @param[in]	len 待校验长度 byte 为单位
 * @retval	校验值
 */

unsigned short _tx_checksum(uint8_t *data, int len)
{
    unsigned short sum = 0;
    for (int i = 0; i < len; i++) {
	sum += data[i];
    }
    return sum;
}

unsigned char _remove_left_zero(unsigned char mask)
{
    if (0 == mask) {
	return 0;
    }
    while (0 == (mask & 0x01)) {
	mask = mask >> 1;
    }
    return mask;
}
/**
 * @brief	探测FPGA是否挂接到总线上
 * @param[in]	dev 设备描述符
 * @retval	0 找到设备
 * @retval	-1 没找到设备
 */
// static unsigned int _fpga_alive(struct fpga_dev *dev)
unsigned int _fpga_alive(struct fpga_dev *dev)
{
    assert(dev != NULL);
    // dev->desc = (char *)dev_desc;
    // return 0;

    // char rbuf[MIN_RX_PACK_SIZE];
    char rbuf[13];
    int  retry = 0;

_again:
    _fpga_transfer(dev, FPGA_ALIVE, NULL, 0, rbuf, ARRAY_SIZE(rbuf));
    unsigned char ack;
    int           offset = 0;

    if (env_ignore_rx) {
	//  CONFIG_IGNORE_FPGA_ALIVE
	// this_dbg("%s() OK CONFIG_IGNORE_FPGA_ALIVE\r\n", __FUNCTION__);
	dev->desc = (char *)dev_desc;
	// dev->mask_amp = _remove_left_zero(CFG_AMP_MASK_LV1) |
	//                 (_remove_left_zero(CFG_AMP_MASK_LV2) << 8) |
	//                 (_remove_left_zero(CFG_AMP_MASK_LV3) << 16) |
	//                 (_remove_left_zero(CFG_AMP_MASK_LV4) << 24);
	// dev->mask_apd = CFG_APD_MASK;
	printf("sdfsdfasaa\r\n");
	return 0;
    }
    dev->desc = (char *)dev_desc;
_CheckFrame:;
    ack = ACK_CODE(rbuf + offset);
    retry++;
    switch (ack) {
    case 0xaa:
	this_dbg("%s() OK\r\n", __FUNCTION__);
	dev->mask_amp = _remove_left_zero(CFG_AMP_MASK_LV1) |
	                (_remove_left_zero(CFG_AMP_MASK_LV2) << 8) |
	                (_remove_left_zero(CFG_AMP_MASK_LV3) << 16) |
	                (_remove_left_zero(CFG_AMP_MASK_LV4) << 24);
	dev->mask_apd = CFG_APD_MASK;
	return 0;
    case 0x55:
	ENV_PRINT_W("Error\r\n");
	break;
    default:
	offset = _find_frame_start(rbuf, ARRAY_SIZE(rbuf) / 2);
	if (retry < RETRY || -1 == offset) {
	    // ENV_PRINT_E("unknow\r\n");
	    offset = 0;
	    break;
	}
	else {
	    goto _CheckFrame;
	}
    }
    if (retry < RETRY) {
	goto _again;
    }
    ENV_PRINT_E("retry time out\r\n");


    return -1;
}
unsigned int com_fpga_alive(struct fpga_dev *dev)
{
    mutex_lock(&dev->mutex);
    int ret = _fpga_alive(dev);
    mutex_unlock(&dev->mutex);
    return ret;
}
unsigned int fpga_alive(struct fpga_dev *dev)
{
    com_fpga_alive(dev);
}
/**
 * @remarks	----    fpga-2016 不实现    ----
 */
int fpga_lcd_bl(struct fpga_dev *dev, int val)
{
    return 0;
}
/**
 * @remarks	----    fpga-2016 不实现    ----
 */
int fpga_charge_status(struct fpga_dev *dev, char *val)
{
    return 0;
}
/**
 * @remarks	----    fpga-2016 不实现    ----
 */
int fpga_low_power(struct fpga_dev *dev, int val)
{
    return 0;
}


int fpga_exist_com_laser(struct fpga_dev *dev, bool *val)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    char rbuf[MIN_RX_PACK_SIZE];

    mutex_lock(&dev->mutex);
    _fpga_transfer(dev, OTDR_COM_LASER, NULL, 0, rbuf, ARRAY_SIZE(rbuf));
    mutex_unlock(&dev->mutex);

    unsigned char ack = ACK_CODE(rbuf);

    switch (ack) {
    case 0xaa:
	this_dbg("%s() exist\r\n", __FUNCTION__);
	*val = true;
	return 0;
    case 0x55:
	this_dbg("%s() free\r\n", __FUNCTION__);
	*val = false;
	return 0;
    default:
	ENV_PRINT_E("unknow\r\n");
	*val = false;
	return -1;
    }
}

/* 接收到的版本信息转换成自然描述 */
#define HW_OFFSET   (11)
/* 文档里要求12byte，2年后赵奎反悔，说用从来没用过的保留位（第8byte），
说12byte内容他不会控制，每次返回都不一样，第8byte他可以控制 */
// #define SOFT_OFFSET (12)
#define SOFT_OFFSET (7)

#define HW_VER(x)   (*(x + HW_OFFSET))
#define SOFT_VER(x) (*(x + SOFT_OFFSET))
#define CH_VER(x)   (*(x + 11))


int com_fpga_version(struct fpga_dev *dev, char *soft_ver, char *hw_ver)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    char rbuf[MIN_RX_PACK_SIZE];

    mutex_lock(&dev->mutex);
    _fpga_transfer(dev, FPGA_VER, NULL, 0, rbuf, ARRAY_SIZE(rbuf));
    mutex_unlock(&dev->mutex);

    unsigned char ack = ACK_CODE(rbuf);
    switch (ack) {
    case 0xaa:
	this_dbg("%s() OK\r\n", __FUNCTION__);
	ENV_PRINT_W("未验证");
	// todu 分离版本号
	*soft_ver = SOFT_VER(rbuf);
	*hw_ver   = HW_VER(rbuf);

	int ver4;
	// printf("拨码开关 %x\n", rbuf[11]);
	// printf("通道数   %x\n", rbuf[12]);
	// printf("保留     %x\n", rbuf[13]);
	memcpy(&ver4, rbuf + 14, 4);
	// printf("版本     %08x\n", ver4);
	return 0;
    case 0x55:
	ENV_PRINT_W("Error\r\n");
	return -1;
    default:
	ENV_PRINT_E("unknow\r\n");
	return -1;
    }
}

extern int com_fpga_info(struct fpga_dev *dev, struct fpga_info *out)
{
    // PRINT_FUTURE("作废%s() 用 fpga_version()代替\r\n", __FUNCTION__);
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    char rbuf[MIN_RX_PACK_SIZE];
    int  ret;

    mutex_lock(&dev->mutex);
    _fpga_transfer(dev, OTDR_VER, NULL, 0, rbuf, ARRAY_SIZE(rbuf));
    mutex_unlock(&dev->mutex);

    unsigned char ack = ACK_CODE(rbuf);
    printf("ack %x\r\n", ack);
    switch (ack) {
    case 0xaa:
	this_dbg("%s() OK\r\n", __FUNCTION__);
	int ver;
	out->hw_ver = rbuf[11];
	out->ch     = rbuf[12];
	memcpy(&ver, rbuf + 14, 4);
	out->soft_ver = ver;
	return 0;
    case 0x55:
	ENV_PRINT_W("Error\r\n");
	return -1;
    default:
	ENV_PRINT_E("unknow\r\n");
	return -1;
    }
}

void PrintfMemory(uint8_t *buf, uint32_t len)
{
    for (uint32_t i = 0; i < len; i++) {
	if (i & 0xf) {
	    printf(" ");
	}
	else {
	    printf("\r\n");
	}
	printf("%2.2x", (unsigned char)*(buf + i));
    }
    printf("\r\n");
}


#if CONFIG_OTDR_PRINT_TX
void _show_cmd_name(unsigned char cmd)
{
    static char *all[] = {
	[0x10] = "OTDR_PARAM",
	[0x11] = "OTDR_START",
	[0x12] = "OTDR_STOP",
	[0x13] = "OTDR_IS_FINISH",
	[0x14] = "OTDR_REDLASER",
	[0xa0] = "OTDR_ALIVE",
	[0x15] = "OTDR_COM_LASER",
	[0xa1] = "OTDR_VER",
	[0x20] = "OTDR_ROTDR",
	[0x21] = "OTDR_APD_TEMP",
	// [0x22]="OTDR_POWER",
	// [0x23]="OTDR_PULSE_ENCODE",
	[0x22] = "CMD_GPIO",
	[0x23] = "CMD_MDIO",
	[0x16] = "OCVL_PARAM",

	[0x25]  = "OTDR_ALARM_APPEAR",
	[0x26]  = "OTDR_ALARM_DISAPPEAR",
	[0x27]  = "OTDR_WD_REG",
	[0x28]  = "OTDR_RD_REG",
	[0x30]  = "OCID_PARAM",
	[0x31]  = "OCID_LEVEL",
	[0x32]  = "OCID_START",
	[0x33]  = "OCID_READ_DATA",
	[0x34]  = "ROUTE_DETECT",
	[0x35]  = "OCID_PARAM_LOSS",
	[0x100] = 0,  // 技巧，用于控制all数组的长度
    };
    if (cmd < 0x100 && cmd > 0) {
	printf("\t%s\r\n", all[cmd]);
    }
    return;
}
#endif


/***************************************************************************
    OTDR 数据读取 功能入口 fpga_read_otdr_data

    fpga_read_otdr_data
        _read_otdr_first
        _read_otdr_serial
        _otdr_data_swap
        _print_otdr_data
        _otdr_checksum
            __checksum
***************************************************************************/

unsigned int _read_otdr_serial(struct fpga_dev *dev, unsigned char *buf, unsigned int byte, unsigned int delay);
void         _print_otdr_data(unsigned long *buf, int len);
int          _otdr_data_swap(unsigned char *buf, int len);
#if defined(CONFIG__read_otdr_1)
unsigned int _read_otdr_1(struct fpga_dev *dev, unsigned char *buf, int size);
#endif
#if defined(CONFIG__read_otdr_first)
static unsigned int _read_otdr_first(struct fpga_dev *dev, unsigned char *buf);
#endif

#if defined(CONFIG_USE_CKSUM)
// static unsigned long __checksum(unsigned char *data, int len);
// unsigned long _otdr_checksum(unsigned char *data, unsigned long len);
#endif

#define ACK_OTDR_FRAME_LEN (18)


/**
 * @brief	从SPI总线上读取若干字节
 * @param[in]	dev 设备描述符
 * @param[out]	buf 读取缓存
 * @param[in]	size 读取多少byte，如果该byte大于驱动缓存（默认4096），
 *		整个ioctl会报错，但函数不会有任何提示
 * @retval	0
 */
#if defined(CONFIG__read_otdr_1)
// static unsigned int _read_otdr_1(struct fpga_dev *dev, unsigned char *buf, int size)
unsigned int _read_otdr_1(struct fpga_dev *dev, unsigned char *buf, int size)
{
    struct spi_ioc_transfer arr[] = {
	{
		.tx_buf    = (unsigned long)NULL,
		.rx_buf    = (unsigned long)buf,
		.len       = size,
		.cs_change = 1,
	},
    };
    ioctl(dev->fd, SPI_IOC_MESSAGE(ARRAY_SIZE(arr)), &arr);
    PrintfMemory(buf, size);
    return 0;
}
#endif
/**
 * @brief	@ref fpga_otdr_isfinish 保证fpga数据准备好后，向FPGA发送读取指令，
            读取otdr数据第一帧，以1000个采样点为一帧，每点4byte.
            _read_otdr_first 不应该被外部应用直接调用，通过对外接口
            @ref fpga_read_otdr_data 间接调用
 * @param[in]		dev 设备描述符
 * @param[in][out]	buf 接受一串otdr数据，此数据缓存有效长度必须大于4000byte
 * @retval	0
 * @see	fpga_otdr_isfinish @see fpga_read_otdr_data
 * @see _read_otdr_serial
 */
#if defined(CONFIG_read_otdr_first)
static unsigned int _read_otdr_first(struct fpga_dev *dev, unsigned char *buf)
{
    char                    tx_head[sizeof(struct fpga_2016)];
    struct fpga_2016       *ptx   = (struct fpga_2016 *)tx_head;
    unsigned short          cksum = 0;
    struct spi_ioc_transfer arr[] = {
	{
		.tx_buf    = (unsigned long)tx_head,
		.rx_buf    = (unsigned long)NULL,
		.len       = sizeof(struct fpga_2016),
		.cs_change = 0,
	},
	{
		.tx_buf    = (unsigned long)NULL,
		.rx_buf    = (unsigned long)NULL,
		.len       = 0,
		.cs_change = 0,
	},
	{
		.tx_buf    = (unsigned long)&cksum,
		.rx_buf    = (unsigned long)NULL,
		.len       = 2,
		.cs_change = 0,
	},
	{
		.tx_buf    = (unsigned long)NULL,
		.rx_buf    = (unsigned long)buf,
		.len       = 4000,
		.cs_change = 1,
	},
    };
    ptx->head[0] = 'G', ptx->head[1] = 'L', ptx->head[2] = 'I', ptx->head[3] = 'N', ptx->head[4] = 'K';
    ptx->len = 10;
    ptx->cmd = OTDR_ROTDR;
    cksum    = OTDR_ROTDR;
    cksum += _tx_checksum((uint8_t *)buf, 0);


    ioctl(dev->fd, SPI_IOC_MESSAGE(ARRAY_SIZE(arr)), &arr);

    return 0;
}
#endif

/**
 * @brief	@ref _read_otdr_first 读取第一帧之后，连续读取otdr数据剩下各帧，
        各帧之间没有任何命令码，以1000个采样点为一帧，每点4byte
        _read_otdr_serial 不应该被外部应用直接调用，通过对外接口

         注意，它没有喂看门狗，不过看门狗都是10几秒
        @ref fpga_read_otdr_data 间接调用
 * @param[in]		dev 设备描述符
 * @param[in][out]	buf 接受一串otdr数据，此数据缓存有效长度必须大于4000byte
 * @param[in]		byte 必须是4的整数倍（产品一个点4byte，32K采样点该值是32000*4）
 * @retval	0
 * @see	_read_otdr_first fpga_read_otdr_data
 */

unsigned int _read_otdr_serial(struct fpga_dev *dev, unsigned char *buf, unsigned int byte, unsigned int delay)
{
    struct spi_ioc_transfer arr[] = {
	{
		.delay_usecs = 1000,
		.tx_buf      = (unsigned long)NULL,
		.rx_buf      = (unsigned long)buf,
#if CONFIG_READ_1000_POINT
		.len = 4000,
#else  // 根据32k或64k修改
		.len = 4000 * 32,
#endif
		.cs_change   = 0,
		.len         = byte,
		.delay_usecs = delay,
	},
    };
    int ret = ioctl(dev->fd, SPI_IOC_MESSAGE(ARRAY_SIZE(arr)), &arr);

    if (ret < arr[0].len) {
	printf("ioctl ret %d\r\n", ret);
    }
    return 0;
}

#define SWAP 1
/**
 * @brief	交换otdr数据
 * @param[in][out]	buf otdr数据流
 * @param[in]		len otdr数据流长度，1 byte为单位
 * @bug	数据内容采用大端格式，由来原因:\n
    fpga在传输数据时已4byte为单位，通常第一个byte最容易错误，如传输如下数据	\n
    0x00030201 0x00060504 						\n
    发送方										\n
    0x00 0x03 0x02 0x01 0x00 0x06 0x05 0x04		\n
    接收方 0xnn可能是乱码						\n
    0xnn 0x03 0x02 0x01 0xnn 0x06 0x05 0x04		\n
    接收方将最高位8bit清0，						\n
    0x00 0x03 0x02 0x01 0x00 0x06 0x05 0x04		\n
    接收方小端格式								\n
    0x01 0x02 0x03 0x00 0x04 0x05 0x06 0x00		\n
    接收以4byte为单位显示						\n
    0x00030201 0x00060504 						\n

 * @see fpga_read_otdr_data
 */

/**
 * @brief	格式化方式"简略"打印otdr数据(以4byte一个点为单位)
 * @param	buf otdr点数据
 * @param	len 点数
 * @remarks 需要编译时使能CONFIG_PRINT_OTDR_DATA，在运行时使能DBG_BIT_OTDR_DATA\n
    打印5000个点格式化:\n
 @code
    ..............0 - 10 (step 1)
    pt0001 pt0002 pt0003 pt0004 pt0005 pt0006 pt0007 pt0008 pt0009 pt0010
    ..............0 ~ 5000  (step 100)
    pt0100 pt0200 pt0300 pt0400 pt0500 pt0600 pt0700 pt0800 pt0900 pt1000
    pt1100 pt1200 pt1300 pt1400 pt1500 pt1600 pt1700 pt1800 pt1900 pt2000
    pt2100 pt2200 pt2300 pt2400 pt2500 pt2600 pt2700 pt2800 pt2900 pt3000
    pt3100 pt3200 pt3300 pt3400 pt3500 pt3600 pt3700 pt3800 pt3900 pt4000
    pt4100 pt4200 pt4300 pt4400 pt4500 pt4600 pt4700 pt4800 pt4900 pt5000
    ..............4991  ~  5000 (step 1)
    pt4991 pt4992 pt4993 pt4994 pt4995 pt4996 pt4997 pt4998 pt4999 pt5000
 @endcode
 */
// void brief_print_data(unsigned long *buf, int len)
void brief_print_data(unsigned int *buf, int len)
{
    if (0 == env_dbg_bit_otdr_data) {
	return;
    }
    unsigned int  *plong;
    unsigned char *pchar;


    printf(C_DEBUG "\n..............0 - 10 (step 1)\n");
    plong = (unsigned int *)buf;

    for (int i = 0; i < 10; i++) {
	printf("%8.8x ", (unsigned int)*plong++);
    }

    printf("\n\n..............0 ~ %d  (step 100)", len);
    plong = (unsigned int *)buf;
    pchar = (unsigned char *)plong;
    // for (int i = 0; i < len / sizeof(unsigned long); i += 100) {
    for (int i = 0; i < len; i += 100) {
	if (i % 1000) {
	    printf(" ");
	}
	else {
	    printf("\n");
	}
	printf("%8.8x", (unsigned int)*(plong + i));
    }

    printf("\n\n..............%d  ~  %d (step 1)\n", len - 10, len);
    plong = (unsigned int *)(buf + len - 10);
    // plong = (unsigned long *)(buf + len- 10);
    for (int i = 0; i < 10; i++) {
	printf("%8.8x ", (unsigned int)*plong);
	plong++;
    }

    printf(C_NORMAL "\n");
}

#if defined(CONFIG_DUMP_OTDR_DATA)
static void _save_file(char *fname, unsigned int *pt, unsigned int len)
{
    FILE *fp;
    fp = fopen(fname, "wb");

    for (int i = 0; i < len; i++) {
	// fprintf(fp, "%8.8x\r\n", *(pt + i) & 0x00ffffff);
	fprintf(fp, "%d\r\n", *(pt + i) & 0x00ffffff);
	// fprintf(fp, "%8.8x\r\n", *(pt + i));
    }
    fclose(fp);
}
#endif


/***************************************************************************
    End OTDR 数据读取 功能入口 fpga_read_otdr_data
***************************************************************************/


#ifdef PRJ_NAME
MODULE_PROJECT(PRJ_NAME);
#endif
#if defined(PRJ_VERSION) && defined(PRJ_PATCHLEVEL) && defined(PRJ_SUBLEVEL)
MODULE_VERSION(PRJ_VERSION "." PRJ_PATCHLEVEL "." PRJ_SUBLEVEL);
#endif

MODULE_BUILD(__DATE__ " " __TIME__);

char str_config[] = "fffa";
MODULE_AUTHOR("MenglongWu <MenglongWoo@aliyun.com>");
MODULE_DEPEND("spi_mxs.ko spidev.ko libpthread.so");
MODULE_DEPEND("Board: TR700");
MODULE_DESCRIPTION("The GLink OTDR FPGA communicate interface");
#ifdef CONFIG_CHK_OTDR_FLAG
PROG_INFO(config, "CONFIG_CHK_OTDR_FLAG=Y");
#else
PROG_INFO(config, "CONFIG_CHK_OTDR_FLAG=N");
#endif
#ifdef CONFIG_USE_CKSUM
PROG_INFO(config, "CONFIG_USE_CKSUM=Y");
#else
PROG_INFO(config, "CONFIG_USE_CKSUM=N");
#endif

#ifdef CONFIG_TEMP_FROM_FPGA
PROG_INFO(config, "CONFIG_TEMP_FROM_FPGA=Y");
#endif
#ifdef CONFIG_TEMP_FROM_ARM
PROG_INFO(config, "CONFIG_TEMP_FROM_ARM=Y");
#endif

#ifdef CONFIG_MAX_SPI_TR_4000BYTE
PROG_INFO(config, "CONFIG_MAX_SPI_TR_4000BYTE=Y");
#endif
#ifdef CONFIG_MAX_SPI_TR_32000BYTE
PROG_INFO(config, "CONFIG_MAX_SPI_TR_32000BYTE=Y");
#endif

PROG_GITSHA1(__GIT_SHA1__);
// #warning("------- 这是一个即将废弃的函数------ddd")


int fpga_if_get_gpio(struct fpga_dev *dev, int io, int *val)
{
    return dev->interface->pfun_get_gpio(dev, io, val);
}
int fpga_if_wrirte_regs(struct fpga_dev *dev, unsigned int base_addr, unsigned int *regs, int len)
{
    return dev->interface->pfun_write_regs(dev, base_addr, regs, len);
}
int fpga_if_write_regs(struct fpga_dev *dev, unsigned int base_addr, unsigned int *regs, int len)
{
    return fpga_if_wrirte_regs(dev, base_addr, regs, len);
}
void fpga_thread(struct fpga_dev *dev)
{
    static pthread_t g_readtimeout;
    pthread_create(&g_readtimeout, NULL, (void *)dev->interface->pfun_workthread, &dev);
}

int fpga_if_set_gpio(struct fpga_dev *dev, int io, int val)
{
    return dev->interface->pfun_set_gpio(dev, io, val);
}
